#include "DoorLock.hpp"

void DoorLock::startAuthentification() {
	const std::string windowID = "previewWindow";

	cvStartWindowThread();
	Screen::getInstance().on();
	cv::namedWindow(windowID, cv::WINDOW_NORMAL);
	cv::setWindowProperty(windowID, CV_WND_PROP_FULLSCREEN,
			CV_WINDOW_FULLSCREEN);

	//display preview for 30 frames.
	for (int i = 0; i < 30; ++i) {
		cv::Mat picture = Camera::getInstance().takeImage();
		cv::putText(picture, "Position your face in the center of the image.",
				cv::Point(20, 20), cv::FONT_HERSHEY_PLAIN, 1,
				cv::Scalar(255, 0, 0));
		cv::imshow(windowID, picture);
		cv::waitKey(100);
	}

	//shoot images for 30 frames and try to auth
	for (int i = 0; i < 30; ++i) {
		cv::Mat picture = Camera::getInstance().takeImage();
		cv::putText(picture, "DON'T MOVE! AUTHORIZING...", cv::Point(20, 20),
				cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(255, 0, 0));
		cv::imshow(windowID, picture);

		cv::Mat formattedPicture = Camera::getInstance().takeFormattedImage();

		bool faceIsKnown = (efts->categorizeFace(formattedPicture)
				== EigenfaceTrainingSet::FC_KNOWN);

		if (faceIsKnown) {
			cv::destroyWindow(windowID);
			Screen::getInstance().off();
			unlockDoor();
			return;
		} else {
			std::cout << "failed to authorize image" << std::endl;
		}

		cv::waitKey(100);
	}

	cv::destroyWindow(windowID);
	Screen::getInstance().off();
	failure();
}

void DoorLock::unlockDoor() {
	std::cout << "door unlocked!" << std::endl;
	ReleaseBuzzer::getInstance().open();
	greenLed->blink(5000);
	ReleaseBuzzer::getInstance().close();
}

void DoorLock::failure() {
	std::cout << "failure!" << std::endl;
	redLed->blink(5000);
}

void DoorLock::hardwareSetup() {
	wiringPiSetupPhys();

	redLed = new Led(11);
	greenLed = new Led(13);
	mainBell = new Bell(18);
	secondaryBell = new Bell(16);
	Camera::getInstance();
}

void DoorLock::eventLoop() {
	Screen::getInstance().off();
	for (;;) {
		delay(100);
		if (secondaryBell->isPressed()) {
			unlockDoor();
		} else if (mainBell->isPressed()) {
			startAuthentification();
		}
	}
}


DoorLock::DoorLock() {
	using namespace std;
	cout << "Initializing hardware..." << endl;

	hardwareSetup();

	cout << "Welcome to the Face Recognizing Door Lock system!" << endl;
	cout << "Enter the path to all Training images: " << endl;

	string path;
	cin >> path;

	while (!FileHelper::folderExists(path)) {
		cout
				<< "ERROR: The specified directory was not found. Enter another path:"
				<< endl;
		cin >> path;
	}

	cout << "Initializing database..." << endl;

	efts = new EigenfaceTrainingSet(
			FileHelper::readImagesInFolder(path, ".jpg"), 100, 100);
	//efts->createDebugImages();

	cout << "Specify the known face threshold: " << endl;
	float knownFaceThreshold;
	cin >> knownFaceThreshold;
	cin.ignore();

	efts->setUnknownFaceThreshold(knownFaceThreshold);

	cout
			<< "Face Recognizing Door Lock system initialized with known face threshold "
			<< knownFaceThreshold << endl;

	eventLoop();
}

DoorLock::~DoorLock() {
	delete greenLed;
	delete redLed;
	delete mainBell;
	delete secondaryBell;
	delete efts;
}
